package com.hp.springbootwebflux.controller;

import com.hp.springbootwebflux.dao.UserRepository;
import com.hp.springbootwebflux.domain.User;
import com.hp.springbootwebflux.util.CheckUtil;
import lombok.AllArgsConstructor;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import javax.validation.Valid;

/**
 * @author dongxing
 **/
@RestController
@RequestMapping("/user")
@AllArgsConstructor(onConstructor_ = {@Autowired})
public class UserController {


    private final UserRepository userRepository;

    /**
     * 以数组的形式一次性返回数据
     *
     * @return
     */
    @GetMapping("/")
    public Flux<User> getAll() {
        return userRepository.findAll();
    }

    /**
     * 以SSE的方式，多次返回数据
     *
     * @return
     */
    @GetMapping(value = "/stream/all", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<User> getStreamAll() {
        return userRepository.findAll();
    }

    /**
     * 新增数据
     *
     * @param user
     * @return
     */
    @PostMapping("/")
    public Mono<User> addUser(@Valid @RequestBody User user) {

        // spring data jpa里面，新增和修改都是save，有id则修改，无id是新增
        // 根据实际情况是否置空id
        user.setId(null);
        CheckUtil.checkNames(user.getName());
        return userRepository.save(user);
    }




    /**
     * 根据id删除用户
     * 存在的时候返回200，不存在返回404
     */
    @DeleteMapping("/{id}")
    public Mono<ResponseEntity<Void>> deleteUser(@PathVariable("id") String id) {

        // deleteById 没有返回值，不能判断数据是都存在
        return this.userRepository.findById(id)
                // 当你要操作数据，并且返回一个Mono这个时候用Flatmap
                // 如果不操作数据，只是转换数据，使用Map
                .flatMap(user -> this.userRepository.delete(user)
                        .then(Mono.just(new ResponseEntity<Void>(HttpStatus.OK))))
                .defaultIfEmpty(new ResponseEntity<Void>(HttpStatus.NOT_FOUND));

    }


    /**
     * 修改数据
     * 存在的时候返回200和修改后的数据，不存在的时候，返回404
     *
     * @param id
     * @return
     */
    @PutMapping("/{id}")
    public Mono<ResponseEntity<User>> updateUser(@PathVariable("id") String id,@Valid @RequestBody User user) {

        CheckUtil.checkNames(user.getName());
        return userRepository.findById(id)
                // flatmap 操作数据
                .flatMap(user1 -> {
                    user1.setAge(user.getAge());
                    user1.setName(user.getName());
                    return userRepository.save(user1);
                })
                // map转换数据
                .map(u -> new ResponseEntity<User>(u, HttpStatus.OK))
                .defaultIfEmpty(new ResponseEntity<User>(HttpStatus.NOT_FOUND))
                ;
    }


    /**
     * 根据id查询用户的信息
     *
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    public Mono<ResponseEntity<User>> findUserById(@PathVariable("id") String id) {
        return userRepository.findById(id).map(user -> new ResponseEntity<User>(user, HttpStatus.OK))
                .defaultIfEmpty(new ResponseEntity<User>(HttpStatus.NOT_FOUND));
    }


    /**
     * 根据年龄查找用户
     *
     * @param start
     * @param end
     * @return
     */
    @GetMapping("/age/{start}/{end}")
    public Flux<User> findUserByAge(@PathVariable("start") int start, @PathVariable("end") int end) {

        userRepository.findUsersByAgeBetween(start, end).subscribe(new Subscriber<User>() {

            private Subscription subscription;

            @Override
            public void onSubscribe(Subscription subscription) {
                this.subscription = subscription;
                subscription.request(1);
            }

            @Override
            public void onNext(User user) {
                System.out.println(user);
                subscription.request(1);
            }

            @Override
            public void onError(Throwable throwable) {
                throwable.printStackTrace();
            }

            @Override
            public void onComplete() {
                subscription.cancel();
            }
        });
        return userRepository.findAllByAgeIsBetween(start, end);
    }

    /**
     * 根据年龄查找用户
     *
     * @param start
     * @param end
     * @return
     */
    @GetMapping(value = "/stream/age/{start}/{end}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<User> streamFindUserByAge(@PathVariable("start") int start, @PathVariable("end") int end) {
        return userRepository.findAllByAgeIsBetween(start, end);
    }


    /**
     * 根据年龄查找用户
     *
     * @return
     */
    @GetMapping("/old")
    public Flux<User> oldUser() {
        return userRepository.oldUser();
    }

    /**
     * 根据年龄查找用户
     *
     * @return
     */
    @GetMapping(value = "/stream/old", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<User> streamOldUser() {
        return userRepository.oldUser();
    }
}
